package org.gov.vis.components;




import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;

import javax.swing.ComboBoxModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

/**
 * The KeyedComboBox model allows to define an internal key (the data element)
 * for every entry in the model. <p/> This class is usefull in all cases, where
 * the public text differs from the internal view on the data. A separation
 * between presentation data and processing data is a prequesite for localizing
 * combobox entries. This model does not allow selected elements, which are not
 * in the list of valid elements.
 * 
 */
public class VISComboBoxModel implements ComboBoxModel {

  /**
   * The internal data carrier to map keys to values and vice versa.
   */
  private static class ComboBoxItemPair {
    /**
     * The key.
     */
    private Object key;

    /**
     * The value for the key.
     */
    private Object value;

    /**
     * Creates a new item pair for the given key and value. The value can be
     * changed later, if needed.
     * 
     * @param key
     *          the key
     * @param value
     *          the value
     */
    public ComboBoxItemPair(final Object key, final Object value) {
      this.key = key;
      this.value = value;
    }

    /**
     * Returns the key.
     * 
     * @return the key.
     */
    public Object getKey() {
      return this.key;
    }

    /**
     * Returns the value.
     * 
     * @return the value for this key.
     */
    public Object getValue() {
      return this.value;
    }

    /**
     * Redefines the value stored for that key.
     * 
     * @param value
     *          the new value.
     */
    public void setValue(final Object value) {
      this.value = value;
    }
  }

  /**
   * The index of the selected item.
   */
  private int selectedItemIndex;

  private Object selectedItemValue;

  /**
   * The data (contains ComboBoxItemPairs).
   */
  private ArrayList data;

  /**
   * The listeners.
   */
  private ArrayList listdatalistener;

  /**
   * The cached listeners as array.
   */
  private transient ListDataListener[] tempListeners;

  private boolean allowOtherValue;

  /**
   * Creates a new keyed combobox model.
   */
  public VISComboBoxModel() {
    this.data = new ArrayList();
    this.listdatalistener = new ArrayList();
  }

  /**
   * Creates a new keyed combobox model for the given keys and values. Keys and
   * values must have the same number of items.
   * 
   * @param keys
   *          the keys
   * @param values
   *          the values
   */
  public VISComboBoxModel(final Object[] keys, final Object[] values) {
    this();
    setData(keys, values);
  }

  
  public VISComboBoxModel(TreeMap<Long,String> _dataMap){
	   this();
	   setData(_dataMap); 
  }//end KComboBoxModel(TreeMap<Long,String> _dataMap)
  
  public void setData(TreeMap<Long,String> _dataMap){
	  Set<Long> keySet = _dataMap.keySet();
	   Object[] _keyArray = new Object[keySet.size()]; 
	   Object[] _valueArray = new Object[keySet.size()];
	   Iterator<Long> keyItr = keySet.iterator();
	   int i=0;
	   while(keyItr.hasNext()){
		 Long key=keyItr.next();
		 String value=_dataMap.get(key);
		 _keyArray[i] = key;
		 _valueArray[i]=value;
		 i++;
	   }
	   
	   setData(_keyArray, _valueArray); 
	  
  }
  
  
  
  public void setData(final Object[][] data){
	  
	    int size = data.length;
	    Object[] keys=new Object[size];
		Object[] values=new Object[size];
		 
		 
		for(int i=0;i<size;i++){
			for(int j=0;j<data[i].length;j++){
				if(j%2==0)
					keys[i] = data[i][j];
				else
					values[i]=data[i][j];
			}
		}
		
		setData(keys, values);
  }
  
  
   
  /**
   * Replaces the data in this combobox model. The number of keys must be equals
   * to the number of values.
   * 
   * @param keys
   *          the keys
   * @param values
   *          the values
   */
  public void setData(final Object[] keys, final Object[] values) {
    if (values.length != keys.length) {
      throw new IllegalArgumentException("Values and text must have the same length.");
    }

    this.data.clear();
    this.data.ensureCapacity(keys.length);

    for (int i = 0; i < values.length; i++) {
      add(keys[i], values[i]);
    }

    this.selectedItemIndex = -1;
    final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, this.data
        .size() - 1);
    fireListDataEvent(evt);
  }

  /**
   * Notifies all registered list data listener of the given event.
   * 
   * @param evt
   *          the event.
   */
  protected synchronized void fireListDataEvent(final ListDataEvent evt) {
    if (this.tempListeners == null) {
      this.tempListeners = (ListDataListener[]) this.listdatalistener
          .toArray(new ListDataListener[this.listdatalistener.size()]);
    }

    final ListDataListener[] listeners = this.tempListeners;
    for (int i = 0; i < listeners.length; i++) {
      final ListDataListener l = listeners[i];
      l.contentsChanged(evt);
    }
  }

  /**
   * Returns the selected item.
   * 
   * @return The selected item or <code>null</code> if there is no selection
   */
  public Object getSelectedItem() {
    return this.selectedItemValue;
  }

  /**
   * Defines the selected key. If the object is not in the list of values, no
   * item gets selected.
   * 
   * @param anItem
   *          the new selected item.
   */
  public void setSelectedKey(final Object anItem) {
    if (anItem == null) {
      this.selectedItemIndex = -1;
      this.selectedItemValue = null;
    } else {
      final int newSelectedItem = findDataElementIndex(anItem);
      if (newSelectedItem == -1) {
        this.selectedItemIndex = -1;
        this.selectedItemValue = null;
      } else {
        this.selectedItemIndex = newSelectedItem;
        this.selectedItemValue = getElementAt(this.selectedItemIndex);
      }
    }
    fireListDataEvent(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1));
  }

  /**
   * Set the selected item. The implementation of this method should notify all
   * registered <code>ListDataListener</code>s that the contents have
   * changed.
   * 
   * @param anItem
   *          the list object to select or <code>null</code> to clear the
   *          selection
   */
  public void setSelectedItem(final Object anItem) {
    if (anItem == null) {
      this.selectedItemIndex = -1;
      this.selectedItemValue = null;
    } else {
      final int newSelectedItem = findElementIndex(anItem);
      if (newSelectedItem == -1) {
        if (isAllowOtherValue()) {
          this.selectedItemIndex = -1;
          this.selectedItemValue = anItem;
        } else {
          this.selectedItemIndex = -1;
          this.selectedItemValue = null;
        }
      } else {
        this.selectedItemIndex = newSelectedItem;
        this.selectedItemValue = getElementAt(this.selectedItemIndex);
      }
    }
    fireListDataEvent(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1));
  }

  private boolean isAllowOtherValue() {
    return this.allowOtherValue;
  }

  /**
   * @param allowOtherValue
   */
  public void setAllowOtherValue(final boolean allowOtherValue) {
    this.allowOtherValue = allowOtherValue;
  }

  /**
   * Adds a listener to the list that's notified each time a change to the data
   * model occurs.
   * 
   * @param l
   *          the <code>ListDataListener</code> to be added
   */
  public synchronized void addListDataListener(final ListDataListener l) {
    if (l == null) {
      throw new NullPointerException();
    }
    this.listdatalistener.add(l);
    this.tempListeners = null;
  }

  /**
   * Returns the value at the specified index.
   * 
   * @param index
   *          the requested index
   * @return the value at <code>index</code>
   */
  public Object getElementAt(final int index) {
    if (index >= this.data.size()) {
      return null;
    }

    final ComboBoxItemPair datacon = (ComboBoxItemPair) this.data.get(index);
    if (datacon == null) {
      return null;
    }
    return datacon.getValue();
  }

  /**
   * Returns the key from the given index.
   * 
   * @param index
   *          the index of the key.
   * @return the the key at the specified index.
   */
  public Object getKeyAt(final int index) {
    if (index >= this.data.size()) {
      return null;
    }

    if (index < 0) {
      return null;
    }

    final ComboBoxItemPair datacon = (ComboBoxItemPair) this.data.get(index);
    if (datacon == null) {
      return null;
    }
    return datacon.getKey();
  }

  /**
   * Returns the selected data element or null if none is set.
   * 
   * @return the selected data element.
   */
  private Object getSelectKey() {
    return getKeyAt(this.selectedItemIndex);
  }

  //Srikanth Vaddepalli
  public Long getSelectedKey() {
	    return (Long)getSelectKey();
	  }
  
  public Integer getSelectedkey() {
	    return (Integer)getSelectKey();
	  }

  /**
   * Returns the length of the list.
   * 
   * @return the length of the list
   */
  public int getSize() {
    return this.data.size();
  }

  /**
   * Removes a listener from the list that's notified each time a change to the
   * data model occurs.
   * 
   * @param l
   *          the <code>ListDataListener</code> to be removed
   */
  public void removeListDataListener(final ListDataListener l) {
    this.listdatalistener.remove(l);
    this.tempListeners = null;
  }

  /**
   * Searches an element by its data value. This method is called by the
   * setSelectedItem method and returns the first occurence of the element.
   * 
   * @param anItem
   *          the item
   * @return the index of the item or -1 if not found.
   */
  private int findDataElementIndex(final Object anItem) {
    if (anItem == null) {
      throw new NullPointerException("Item to find must not be null");
    }

    for (int i = 0; i < this.data.size(); i++) {
      final ComboBoxItemPair datacon = (ComboBoxItemPair) this.data.get(i);
      if (anItem.equals(datacon.getKey())) {
        return i;
      }
    }
    return -1;
  }

  /**
   * Tries to find the index of element with the given key. The key must not be
   * null.
   * 
   * @param key
   *          the key for the element to be searched.
   * @return the index of the key, or -1 if not found.
   */
  public int findElementIndex(final Object key) {
    if (key == null) {
      throw new NullPointerException("Item to find must not be null");
    }

    for (int i = 0; i < this.data.size(); i++) {
      final ComboBoxItemPair datacon = (ComboBoxItemPair) this.data.get(i);
      if (key.equals(datacon.getValue())) {
        return i;
      }
    }
    return -1;
  }

  /**
   * Removes an entry from the model.
   * 
   * @param key
   *          the key
   */
  public void removeDataElement(final Object key) {
    final int idx = findDataElementIndex(key);
    if (idx == -1) {
      return;
    }

    this.data.remove(idx);
    final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, idx, idx);
    fireListDataEvent(evt);
  }

  /**
   * Adds a new entry to the model.
   * 
   * @param key
   *          the key
   * @param cbitem
   *          the display value.
   */
  public void add(final Object key, final Object cbitem) {
    final ComboBoxItemPair con = new ComboBoxItemPair(key, cbitem);
    this.data.add(con);
    final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, this.data
        .size() - 2, this.data.size() - 2);
    fireListDataEvent(evt);
  }

  /**
   * Removes all entries from the model.
   */
  public void clear() {
    final int size = getSize();
    this.data.clear();
    final ListDataEvent evt = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, 0, size - 1);
    fireListDataEvent(evt);
  }

}
